home *** CD-ROM | disk | FTP | other *** search
- /* MouseDemo.c */
- /*
- * Mouse selection mainline.
- *
- * Copyright © 1989 Martin Minow. All rights reserved.
- *
- * You may incorporate portions of this program in your
- * applications without restriction as long as this
- * copyright notice remains intact and the applications
- * are not sold for profit and this source is not
- * redistributed for profit.
- */
- #include "TrackEdit.h"
- /*
- * Set DEBUG 1 to make a very small window so you can
- * use the Think C debugger without getting unwanted
- * window update events.
- */
- #define DEBUG 0
- #define NIL (0L)
- #define TOP_MARGIN 4
- #define SIDE_MARGIN 4
- #define sBarWidth 15 /* Scroll bar width */
- #define THE_FONT "\pHelvetica"
- #define FONT_SIZE 18
- /*
- * We always store the current TrackHandle in a local
- * variable named track_handle.
- */
- #define TR (**track_handle)
- /*
- * height and width define the extants of a rectangle.
- */
- #define height(r) ((r).bottom - (r).top)
- #define width(r) ((r).right - (r).left)
-
- /*
- * Menu organization
- */
- enum Menus {
- MENU_Apple = 1,
- MENU_File = 256,
- MENU_Edit = 257,
- MENU_Ctrl = 258
- };
-
- enum Apple_Menu {
- Apple_About = 1
- };
-
- enum File_Menu {
- File_Debug = 1,
- Unused1,
- File_Reinitialize,
- Unused2,
- File_Quit
- };
-
- enum Edit_Menu {
- Edit_Undo = 1,
- Edit_Skip,
- Edit_Cut,
- Edit_Copy,
- Edit_Paste,
- Edit_Clear
- };
-
- enum Control_Menu {
- Ctrl_Script = 1,
- Ctrl_Smart,
- Ctrl_Unused1,
- Ctrl_Hilite,
- Ctrl_Caret,
- Ctrl_ObeyCR,
- Ctrl_AutoScroll,
- Ctrl_Unused2,
- Ctrl_JustLeft, /* Keep in */
- Ctrl_JustCenter, /* this */
- Ctrl_JustRight /* order. */
- };
-
- #define keyCodeShift 8
- enum Arrow_Keys {
- /*
- * ADB keyboard arrow keys and keypad keys
- */
- Left_Arrow = (0x7B << keyCodeShift),
- Right_Arrow = (0x7C << keyCodeShift),
- Down_Arrow = (0x7D << keyCodeShift),
- Up_Arrow = (0x7E << keyCodeShift),
- Home_Key = (0x73 << keyCodeShift),
- End_Key = (0x77 << keyCodeShift),
- Pg_Down_Key = (0x74 << keyCodeShift),
- Pg_Up_Key = (0x79 << keyCodeShift),
- Help_Key = (0x72 << keyCodeShift),
- /*
- * Mac-Plus arrow keys.
- */
- Right_Plus = (0x42 << keyCodeShift),
- Left_Plus = (0x46 << keyCodeShift),
- Down_Plus = (0x48 << keyCodeShift),
- Up_Plus = (0x4D << keyCodeShift)
- };
-
- /*
- * This is the data shown in the display.
- */
- char fubar[] =
- "The term FUBAR actually first appeared during the reign"
- " of Queen Anne of England (1702-1714), the last ruling"
- " sovereign of the Stuart Dynasty (1603-1714). The Duke"
- " of Marlborough (1650-1722), John Churchill, Sir"
- " Winston’s great great… grandfather, after his great"
- " victory at the battle of Blenhiem (August 13, 1704)"
- " against the French, in Austria, had some captured"
- " French dispatches translated. The translator,"
- " unfortunately unknown, but believed to be a Lance"
- " Corporal in the Royal Guards, having some difficulty"
- " translating a slang French expression used by Marshall"
- " Tallard, the defeated French general, gave up in"
- " despair and wrote in FUBAR; which, although not"
- " literally translating the dispatch, expressed the"
- " French general’s analysis of the situation.\r"
- "Smith-Huxley, J.P., “The Augustan Age of Good Queen"
- " Anne,” pp 386-387, R. Clay Ltd, London, (1903)"
- " SBN 384-82210-2.";
-
- #define FUBAR_SIZE (sizeof fubar - 1) /* No NUL trail */
-
- WindowPtr the_window;
- TrackHandle the_track_handle;
- MenuHandle apple_menu;
- MenuHandle file_menu;
- MenuHandle edit_menu;
- MenuHandle ctrl_menu;
-
- /*
- * Justification flags. Keep in this order.
- */
- INTEGER justify[] = {
- trackJustLeft, trackJustCenter, trackJustRight
- };
- Boolean do_autoscroll;
-
- /*
- * These variables manage transfers to/from the desk
- * scrap. See Chernicoff, Macintosh Revealed, Vol 2.
- */
- Boolean scrap_changed; /* TRUE after Cut/Copy */
- INTEGER scrap_count; /* ZeroScrap counter */
- /*
- * Prototypes
- */
- void do_command(long);
- void do_mouse(EventRecord);
- void enable_edit_menu(TrackHandle, Boolean);
- void get_desk_scrap(void);
- void keyin(TrackHandle, EventRecord);
- void main(void);
- pascal void my_caret(Rect *, TrackPtr);
- pascal void my_hilite(Rect *, TrackPtr);
- void put_desk_scrap(void);
- void setup(void);
- void get_text_box(Rect *, WindowPtr);
-
- /*
- * main()
- * Mainline: initialize the application, then process
- * mouse and menu events.
- */
- void
- main()
- {
- Boolean is_event;
- WindowPtr window;
- EventRecord event;
- GrafPtr save_port;
- TrackHandle track_handle;
- Rect box;
-
- setup();
- for (;;) {
- SystemTask();
- TrackIdle(the_track_handle);
- is_event = GetNextEvent(everyEvent, &event);
- if (is_event) {
- if (event.what == activateEvt
- || event.what == updateEvt)
- window = (WindowPtr) event.message;
- else {
- window = FrontWindow();
- }
- if (window != the_window)
- track_handle = NIL;
- else {
- track_handle = (TrackHandle) GetWRefCon(window);
- if (track_handle != NIL
- && track_handle != the_track_handle)
- DebugStr("\pBogus track_handle");
- }
- switch (event.what) {
- case mouseDown:
- do_mouse(event);
- break;
- case keyDown:
- case autoKey:
- keyin(track_handle, event);
- break;
- case activateEvt:
- /*
- * Activate or deactivate the Track record
- * as needed. Also, if we are going to/from
- * a desk accessory (or another application),
- * copy the desk scrap and enable/disable
- * appropriate edit menu options.
- */
- if (track_handle != NIL
- && window == the_window) {
- if ((event.modifiers & activeFlag) != 0) {
- TrackActivate(track_handle);
- get_desk_scrap();
- enable_edit_menu(track_handle, FALSE);
- }
- else /* deactivating */ {
- TrackDeactivate(track_handle);
- put_desk_scrap();
- enable_edit_menu(track_handle, TRUE);
- }
- }
- DrawGrowIcon(window);
- break;
- case updateEvt:
- if (window == the_window
- && track_handle != NIL) {
- GetPort(&save_port);
- SetPort(window);
- BeginUpdate(window);
- EraseRect(&window->portRect);
- /*
- * Use a local copy of the viewRect in case
- * the (unlocked) TrackRecord moves.
- */
- box = TR.viewRect;
- TrackUpdate(&box, track_handle);
- #if TOP_MARGIN != 0 && SIDE_MARGIN != 0
- InsetRect(&box, -1, -1);
- FrameRect(&box);
- #endif
- /*
- * Must follow TrackUpdate
- */
- DrawGrowIcon(window);
- EndUpdate(window);
- SetPort(save_port);
- }
- break;
- default:
- break;
- }
- }
- }
- }
-
- /*
- * Handle keystrokes. Most of this is needed for
- * arrow-key scrolling.
- */
- static void
- keyin(track_handle, event)
- TrackHandle track_handle;
- EventRecord event;
- {
- INTEGER c;
- LONGINT choice;
- LONGINT hdelta, hscroll, hmax;
- LONGINT vdelta, vscroll, vmax;
-
- /*
- * The arrow keys scroll the window.
- * <Option><Arrow> scrolls single pixels.
- *
- * [h,v]max The largest amount we will
- * scroll the rectangle.
- * [h,v]delta The amount the arrow key scrolls.
- * [h,v]scroll The amount we actually scroll.
- */
- hmax = TR.lineWidth - width(TR.viewRect);
- vmax = (TR.nLines * TR.lineHeight)
- + TR.fontDescent
- - height(TR.viewRect);
- hdelta = vdelta = TR.lineHeight;
- if ((event.modifiers & optionKey) != 0)
- hdelta = vdelta = 1;
- hscroll = vscroll = 0;
- switch (event.message & keyCodeMask) {
- case Left_Arrow: case Left_Plus:
- hscroll = -hdelta; goto do_scroll;
- case Right_Arrow: case Right_Plus:
- hscroll = hdelta; goto do_scroll;
- case Up_Arrow: case Up_Plus:
- vscroll = -vdelta; goto do_scroll;
- case Down_Arrow: case Down_Plus:
- vscroll = vdelta; goto do_scroll;
- case Pg_Up_Key: /* Up one screen */
- vscroll = (-height(TR.viewRect)); goto do_scroll;
- case Pg_Down_Key: /* Down one screen */
- vscroll = height(TR.viewRect); goto do_scroll;
- case Home_Key: /* Scroll to start of text */
- hscroll = -TR.leftPixel;
- vscroll = -TR.topPixel; goto do_scroll;
- case End_Key: /* Scroll to end of text */
- hscroll = -TR.leftPixel + hmax;
- vscroll = -TR.topPixel + vmax;
- /*
- * Pin the scroll amount against the
- * boundaries of the document and scroll
- * if anything changes. Note that we can't
- * determine the maximum width of the document
- * if lines are only delimited by <return>.
- */
- do_scroll:
- if (hscroll != 0 || vscroll != 0)
- TrackPinScroll(hscroll, vscroll, track_handle);
- break;
- case Help_Key:
- TrackSelView(track_handle);
- break;
- default:
- c = event.message & charCodeMask;
- if ((event.modifiers & cmdKey) != 0) {
- if (event.what == keyDown) {
- choice = MenuKey(c);
- if (HiWord(choice) != 0)
- do_command(choice);
- else {
- SysBeep(10); /* Bogus <cmd> */
- }
- }
- }
- else if (track_handle != NIL)
- TrackKey(c, track_handle);
- }
- }
- /*
- * do_mouse(event)
- * Process a mouse button press, calling handlers as
- * needed.
- */
- static void
- do_mouse(event)
- EventRecord event;
- {
- WindowPtr window;
- register int which_part;
- Rect box;
- int kind;
- TrackHandle track_handle;
- long new;
-
- which_part = FindWindow(event.where, &window);
- switch (which_part) {
- case inDesk:
- SysBeep(2);
- break;
- case inMenuBar:
- do_command(MenuSelect(event.where));
- break;
- case inSysWindow:
- SystemClick(&event, window);
- break;
- case inGoAway:
- if (window == the_window
- && TrackGoAway(window, event.where))
- ExitToShell();
- else {
- kind = ((WindowPeek) window)->windowKind;
- if (kind < 0) /* Desk accessory? */
- CloseDeskAcc(kind);
- }
- break;
- case inDrag:
- box = screenBits.bounds;
- box.top += GetMBarHeight();
- InsetRect(&box, 2, 4);
- DragWindow(window, event.where, &box);
- break;
- case inGrow:
- box = screenBits.bounds;
- box.left = 64 + sBarWidth;
- box.top = 64 + sBarWidth;
- box.bottom -= GetMBarHeight();
- new = GrowWindow(window, event.where, &box);
- if (new != 0) {
- track_handle = (TrackHandle) GetWRefCon(window);
- EraseRect(&window->portRect);
- SizeWindow(window, LoWord(new), HiWord(new), TRUE);
- InvalRect(&window->portRect);
- get_text_box(&TR.viewRect, window);
- }
- break;
- case inContent:
- if (FrontWindow() != window)
- SelectWindow(window);
- else {
- SetPort(window);
- track_handle = (TrackHandle) GetWRefCon(window);
- GlobalToLocal(&event.where);
- TrackClick(
- event.where,
- (event.modifiers & shiftKey) != 0,
- track_handle
- );
- enable_edit_menu(track_handle, FALSE);
- }
- break;
- }
- }
-
- /*
- * Private hilite function (see Inside Mac I-379).
- * Hilite the selection by underlining it.
- */
- pascal void
- my_hilite(boxp, tr)
- Rect *boxp;
- TrackPtr tr;
- {
- Rect box;
-
- box = *boxp;
- box.top = box.bottom;
- --box.top;
- InvertRect(&box);
- }
-
- /*
- * Private caret function (see Inside Mac I-379).
- * Draw the selection as a nice TextEdit vertical line.
- */
- pascal void
- my_caret(boxp, tr)
- Rect *boxp;
- TrackPtr tr;
- {
- InvertRect(boxp);
- }
-
- /*
- * do_command(which_item)
- * Process menu bar commands.
- */
- void
- do_command(choice)
- long choice;
- {
- int item;
- register int i;
- Str255 name;
- GrafPtr save_port;
- int old_option;
- int the_class;
- TrackHandle track_handle;
- WindowPtr window;
-
- window = FrontWindow();
- track_handle = (TrackHandle) GetWRefCon(window);
- if (track_handle != the_track_handle)
- DebugStr("\pStrange front window");
- item = LoWord(choice);
- switch (HiWord(choice)) {
- case MENU_Apple:
- GetItem(apple_menu, item, &name);
- if (item == Apple_About)
- SysBeep(10); /* No Mouse About */
- else {
- /*
- * Launch a desk accessory: enable the entire Edit
- * menu, save the port, call the accessory, then
- * restore our state.
- */
- enable_edit_menu(track_handle, TRUE);
- GetPort(&save_port);
- OpenDeskAcc(name);
- SetPort(save_port);
- enable_edit_menu(track_handle, FALSE);
- }
- break;
- case MENU_File:
- switch (item) {
- case File_Debug:
- Debugger();
- break;
- case File_Reinitialize:
- TrackSetText(fubar, FUBAR_SIZE, track_handle);
- break;
- case File_Quit:
- ExitToShell();
- }
- break;
- case MENU_Edit:
- if (!SystemEdit(item - 1)) {
- switch (item) {
- case Edit_Undo:
- break;
- case Edit_Cut:
- TrackCut(track_handle);
- scrap_changed = TRUE;
- break;
- case Edit_Copy:
- TrackCopy(track_handle);
- scrap_changed = TRUE;
- break;
- case Edit_Paste:
- TrackPaste(track_handle);
- break;
- case Edit_Clear:
- TrackDelete(track_handle);
- break;
- }
- }
- enable_edit_menu(track_handle, FALSE);
- break;
- case MENU_Ctrl:
- switch (item) {
- case Ctrl_Script:
- _Track_flip(
- *track_handle, _Track_use_script_manager);
- CheckItem(
- ctrl_menu,
- Ctrl_Script,
- _Track_is_set(
- *track_handle, _Track_use_script_manager)
- );
- break;
- case Ctrl_Smart:
- _Track_flip(
- *track_handle, _Track_use_smart_cut_paste);
- CheckItem(
- ctrl_menu,
- Ctrl_Smart,
- _Track_is_set(
- *track_handle, _Track_use_smart_cut_paste)
- );
- break;
- case Ctrl_Hilite:
- TrackDeactivate(track_handle);
- if (TR.highHook == NIL)
- TR.highHook = (ProcPtr) my_hilite;
- else {
- TR.highHook = NIL;
- }
- TrackActivate(track_handle);
- CheckItem(
- ctrl_menu, Ctrl_Hilite, (TR.highHook != NIL));
- break;
- case Ctrl_Caret:
- TrackDeactivate(track_handle);
- if (TR.caretHook == NIL)
- TR.caretHook = (ProcPtr) my_caret;
- else {
- TR.caretHook = NIL;
- }
- TrackActivate(track_handle);
- CheckItem(
- ctrl_menu, Ctrl_Caret, (TR.caretHook != NIL));
- break;
- case Ctrl_ObeyCR:
- TR.crOnly = (TR.crOnly == 0) ? -1 : 0;
- TrackCalText(track_handle);
- CheckItem(
- ctrl_menu, Ctrl_ObeyCR, (TR.crOnly < 0));
- break;
- case Ctrl_AutoScroll:
- do_autoscroll = !do_autoscroll;
- TrackAutoView(do_autoscroll, track_handle);
- CheckItem(
- ctrl_menu, Ctrl_AutoScroll, do_autoscroll);
- break;
- case Ctrl_JustLeft:
- case Ctrl_JustCenter:
- case Ctrl_JustRight:
- TrackSetJust(
- justify[item - Ctrl_JustLeft], track_handle);
- for (i = Ctrl_JustLeft; i <= Ctrl_JustRight; i++)
- CheckItem(ctrl_menu, i, (item == i));
- }
- break;
- }
- HiliteMenu(0);
- }
-
- /*
- * enable_edit_menu(track_handle, is_desk_accessory)
- * Enable/disable edit menu items. All are enabled if
- * we're starting a desk accessory. If not, Enable the
- * Cut, Copy, and Clear options if there's a selection,
- * and Paste if there's something in the track scrap.
- * Note that we don't support Undo.
- */
- void
- enable_edit_menu(track_handle, starting_desk)
- TrackHandle track_handle;
- Boolean starting_desk;
- {
- if (starting_desk) {
- EnableItem(edit_menu, Edit_Undo);
- EnableItem(edit_menu, Edit_Cut);
- EnableItem(edit_menu, Edit_Copy);
- EnableItem(edit_menu, Edit_Paste);
- EnableItem(edit_menu, Edit_Clear);
- }
- else {
- DisableItem(edit_menu, Edit_Undo);
- if (TrackGetSelectionLength(track_handle) > 0) {
- EnableItem(edit_menu, Edit_Cut);
- EnableItem(edit_menu, Edit_Copy);
- EnableItem(edit_menu, Edit_Clear);
- }
- else {
- DisableItem(edit_menu, Edit_Cut);
- DisableItem(edit_menu, Edit_Copy);
- DisableItem(edit_menu, Edit_Clear);
- }
- if (TrackGetScrapLen() != 0)
- EnableItem(edit_menu, Edit_Paste);
- else {
- DisableItem(edit_menu, Edit_Paste);
- }
- }
- }
-
- /*
- * get_desk_scrap()
- * If there is a TEXT item in the desk scrap, read it in
- * and load it into the Track scrap. The algorithm is
- * adapted from Chernicoff, Macintosh Revealed, vol. 2.
- */
- void
- get_desk_scrap()
- {
- long offset;
- long length; /* Scrap non-empty? */
-
- /*
- * If the desk scrap contents have changed or
- * the scrap hasn't been initialized, read it
- * and load the Track private scrap.
- */
- if (scrap_count != InfoScrap()->scrapCount
- || InfoScrap()->scrapState < 0) {
- /*
- * The scrap has changed, check for a text item.
- */
- length = GetScrap(NIL, 'TEXT', &offset);
- if (length < 0 || TrackFromScrap() != noErr)
- length = -1; /* signal error */
- if (length > 0) /* non-empty scrap? */
- EnableItem(edit_menu, Edit_Paste);
- else {
- TrackSetScrapLen(0); /* Make it empty */
- DisableItem(edit_menu, Edit_Paste);
- }
- }
- scrap_count = InfoScrap()->scrapCount;
- }
-
- /*
- * put_desk_scrap()
- * Copy the Track scrap to the desk scrap. Algorithm
- * adapted from Chernicoff, Macintosh Revealed, Vol 2.
- */
- void
- put_desk_scrap()
- {
- OSErr status;
-
- if (scrap_changed) {
- scrap_count = ZeroScrap();
- status = TrackToScrap();
- if (status != noErr)
- DebugStr("\pCan't write scrap.");
- scrap_changed = FALSE;
- }
- }
-
- /*
- * setup()
- * One-time initialization.
- */
- static void
- setup()
- {
- int font_number;
- TrackHandle track_handle;
- Rect box;
-
- /*
- * Normal Macintosh initialization.
- */
- InitGraf(&thePort);
- InitFonts();
- FlushEvents(everyEvent, 0);
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(NIL);
- InitCursor();
- MaxApplZone();
- /*
- * Initialize mouse track library.
- */
- TrackInit();
- /*
- * Create the menus and check off the
- * TrackHandle flags.
- */
- apple_menu = NewMenu(MENU_Apple, "\p\024");
- file_menu = NewMenu(MENU_File, "\pFile");
- edit_menu = NewMenu(MENU_Edit, "\pEdit");
- ctrl_menu = NewMenu(MENU_Ctrl, "\pOptions");
- AppendMenu(apple_menu, "\p(No Mouse About;(-");
- AddResMenu(apple_menu, 'DRVR');
- AppendMenu(
- file_menu,
- "\pDebug/.;(-;Reinitialize;(-;Quit/Q"
- );
- AppendMenu(
- edit_menu,
- "\pUndo/Z;(-;Cut/X;Copy/C;Paste/V;Clear"
- );
- AppendMenu(
- ctrl_menu,
- "\pScriptManager;Intelligence;(-;"
- "My Hilite;My Caret;No word wrap;Auto-scroll;(-;"
- "Left Justify;Center Justify;Right Justify"
- );
- InsertMenu(apple_menu, 0);
- InsertMenu(file_menu, 0);
- InsertMenu(edit_menu, 0);
- InsertMenu(ctrl_menu, 0);
- DrawMenuBar();
- /*
- * Create the display window, set the proper font,
- * and set the TrackHandle in the window's refCon.
- */
- box = screenBits.bounds;
- box.top += GetMBarHeight() * 2;
- #if DEBUG
- box.bottom = 160;
- box.left += 20;
- box.right -= 20;
- #endif
- the_window = NewWindow(
- NIL, /* Allocate storage */
- &box, /* Display Rect */
- "\pMouse Demo", /* Title */
- TRUE, /* Visible on creation */
- documentProc, /* Window type */
- -1L, /* Show in front */
- FALSE, /* no GoAway box */
- NIL /* RefCon */
- );
- SetPort(the_window);
- GetFNum(THE_FONT, &font_number);
- TextFont(font_number);
- TextSize(FONT_SIZE);
- get_text_box(&box, the_window);
- track_handle = TrackNew(box.right - box.left, &box);
- the_track_handle = track_handle;
- SetWRefCon(the_window, (LONGINT) track_handle);
- TrackSetText(fubar, FUBAR_SIZE, track_handle);
- CheckItem(
- ctrl_menu,
- Ctrl_Script,
- _Track_is_set(
- *track_handle, _Track_use_script_manager)
- );
- CheckItem(
- ctrl_menu,
- Ctrl_Smart,
- _Track_is_set(
- *track_handle, _Track_use_smart_cut_paste)
- );
- CheckItem(ctrl_menu, Ctrl_JustLeft, TRUE);
- CheckItem(ctrl_menu, Ctrl_AutoScroll, TRUE);
- do_autoscroll = TRUE;
- TrackAutoView(do_autoscroll, track_handle);
- }
-
- /*
- * get_text_box()
- * Locate the display text in the window.
- */
- void
- get_text_box(boxp, window)
- register Rect *boxp;
- WindowPtr window;
- {
- *boxp = window->portRect;
- boxp->right -= sBarWidth;
- boxp->bottom -= sBarWidth;
- InsetRect(boxp, TOP_MARGIN, SIDE_MARGIN);
- }
-